﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LightPersist.Exceptions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestDomainModel;

namespace LightPersistTests
{
	[TestClass]
	public class IsInverted :  TripleTestsBase
	{
		[TestMethod]
		public void Should_Return_Null_if_there_is_no_Parent()
		{
			var newChild = Context.Create<FakeControl>();
			Root.MainControl = newChild;

			Reconnect();
			var persistChild = Context.GetObjectByID<FakeControl>(newChild.ID);

			Assert.IsNull(persistChild.Parent);
		}

		[TestMethod]
		public void Should_Return_inverse_property()
		{
			var newChild = Context.Create<FakeControl>();
			var parentControl = Root.Children[0];
			parentControl.Children.Add(newChild);

			Reconnect();

			var persistChild = Context.GetObjectByID<FakeControl>(newChild.ID);
			Assert.IsNotNull(persistChild.Parent);
			Assert.AreSame(Root.Children[0], persistChild.Parent);
		}

		[TestMethod]
		public void Should_return_null_if_inverse_property_has_another_type()
		{
			Reconnect();
			child = Context.GetObjectByID<FakeControl>(childID);
			Assert.IsNull(child.Parent,"FakeRoot has another type (not FakeControl)");
		}

		[TestMethod]
		public void Should_not_allow_create_2_parents()
		{
			Root.Children.Add(Context.Create<FakeControl>());
			var parent1 = Root.Children[0];
			var parent2 = Root.Children[1];

			var newChild = Context.Create<FakeControl>();

			parent1.Children.Add(newChild);

			Reconnect();

			Context.GetObjectByID(RootGuid);

			Throws<LightPersistException>(() => Context.GetObjectByID<FakeControl>(parent2.ID).Children.Add(newChild));

			// ensure transaction are invalidated. This is very important to model consistency!
			Throws<TransactionException>(() => tr.CommitTransaction());
		}

		[TestMethod]
		public void Should_works_with_inverse_of_lists()
		{
			var animation1 = Context.Create<FakeAnimation>();
			var animation2 = Context.Create<FakeAnimation>();
			Root.Animations.Add(animation1);
			Root.Animations.Add(animation2);

			Reconnect();

			animation1 = Context.GetObjectByID<FakeAnimation>(animation1.ID);
			animation2 = Context.GetObjectByID<FakeAnimation>(animation2.ID);
			child = Context.GetObjectByID<FakeControl>(childID);

			// do not allow modify readonly list (invers of)
			Throws<LightPersistException>(() => child.Animations.Add(animation1));

			animation1.Controls.Add(child);
			animation2.Controls.Add(child);

			Reconnect();
			child = Context.GetObjectByID<FakeControl>(childID);

			Equal(2, child.Animations.Count);
			Equal(animation1.ID, child.Animations[0].ID);
			Equal(animation2.ID, child.Animations[1].ID);
		}

		[TestMethod]
		public void Should_works_with_inverse_of_lists__remove()
		{
			var animation1 = Context.Create<FakeAnimation>();
			Root.Animations.Add(animation1);
			animation1.Controls.Add(child);
			Reconnect();
			child = Context.GetObjectByID<FakeControl>(childID);
			animation1 = Context.GetObjectByID<FakeAnimation>(animation1.ID);
			Equal(1, child.Animations.Count);

			animation1.Controls.Clear();
			Reconnect();
			child = Context.GetObjectByID<FakeControl>(childID);
			Equal(0, child.Animations.Count);
		}
	}
}
